package com.ddxz.demo.liquibase.service.impl;

import com.ddxz.demo.liquibase.dto.TenantInfo;
import com.ddxz.demo.liquibase.entity.*;
import com.ddxz.demo.liquibase.mapper.TenantMapper;
import com.ddxz.demo.liquibase.service.LiquibaseService;
import com.ddxz.tool.core.common.CommonUtil;
import com.ddxz.tool.core.convert.BeanUtil;
import com.ddxz.tool.core.convert.StringUtil;
import com.ddxz.tool.core.security.SecurityUtil;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.integration.spring.SpringLiquibase;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * class description
 *
 * @author 朱宗刚
 * @version 1.0.0
 * @date 2020/12/17
 */

@Service
public class LiquibaseServiceImpl implements LiquibaseService {
    @Override
    public void updateTenant(String tenant) {
        try {
            DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());
            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
            database.setLiquibaseSchemaName(tenant);
            database.setDefaultSchemaName(tenant);
            mapper.createTenant(tenant);
            Liquibase li = new Liquibase("liquibase/postgres-normal-tenant.xml", new ClassLoaderResourceAccessor(), database);
            li.update(liquibase.getContexts());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void initTenantData(TenantInfo tenant) {
        String deptId = initDepartment(tenant);
        // 初始化岗位信息并返回信息化岗位的标识
        String postId = initPost(tenant.getCode());
        Map<String, String> users = initUser(tenant.getCode(), deptId, postId);
        Map<String, String> roles = initRole(tenant.getCode());
        initMenu(tenant.getCode(), roles);
        initUserRole(tenant.getCode(), users, roles);
    }

    @Override
    public void saveTenant(TenantInfo tenant) {
        TenantEntity entity = new TenantEntity();
        BeanUtil.copyProperties(tenant, entity);
        if(StringUtil.isEmpty(tenant.getId())) {
            entity.setId(CommonUtil.generatorId("t_tenant"));
        }
        mapper.saveTenant(entity, supperTenant);
    }

    private void initMenu(String code, Map<String, String> roles) {

    }

    private void initUserRole(String code, Map<String, String> users, Map<String, String> roles) {
        Map<String, String> relation = new HashMap<String, String>(){{
            put("admin", "SYSTEM_ADMIN"); put("auditor", "SYSTEM_AUDITOR");
            put("safety", "SYSTEM_SAFETY"); put("manager", "DATA_MANAGER");
            put("operator", "DATA_OPERATOR");
        }};
        users.forEach((username, userId) -> {
            UserRoleEntity entity = new UserRoleEntity(userId, roles.get(relation.get(username)));
            mapper.saveUserRoleRelation(entity, code);
        });
    }

    private Map<String, String> initUser(String code, String deptId, String postId) {
        Map<String, String> users = new HashMap<String, String>(5) {{
            put("admin", SecurityUtil.md5("admin@Admin@123"));
            put("auditor", SecurityUtil.md5("auditor@Auditor@123"));
            put("safety", SecurityUtil.md5("safety@Safety@123"));
            put("manager", SecurityUtil.md5("manager@Manager@123"));
            put("operator", SecurityUtil.md5("operator@Operator@123"));
        }};

        for(Map.Entry<String, String> entry : users.entrySet()) {
            UserEntity entity = new UserEntity(entry.getKey(), entry.getValue(), deptId, postId);
            mapper.saveUser(entity, code);
            users.replace(entry.getKey(), entity.getId());
        }

        return users;
    }

    private Map<String, String> initRole(String code) {
        Map<String, String> map = new HashMap<String, String>(6) { {
            put("SYSTEM_ADMIN", "系统管理员"); put("SYSTEM_AUDITOR", "系统审计员");
            put("SYSTEM_SAFETY", "系统保密员"); put("DATA_MANAGER", "数据管理员");
            put("DATA_OPERATOR", "数据操作员"); put("DATA_NORMAL", "数据用户");
        }};

        for (Map.Entry<String, String> entry : map.entrySet()) {
            RoleEntity entity = new RoleEntity(entry.getValue(), entry.getKey());
            mapper.saveRole(entity, code);
            map.replace(entry.getKey(), entity.getId());
        }

        return map;
    }

    private String initPost(String code) {
        PostEntity entity = new PostEntity();
        entity.setName("信息化工程师");
        mapper.savePost(entity, code);
        return entity.getId();
    }

    private String initDepartment(TenantInfo tenant) {
        DepartmentEntity entity = new DepartmentEntity();
        entity.setName(tenant.getName());
        entity.setFullname(tenant.getFullname());
        entity.setDescription(tenant.getDescription());
        mapper.saveDepartment(entity, tenant.getCode());
        return entity.getId();
    }

    private final DataSource dataSource;

    private final SpringLiquibase liquibase;

    private final TenantMapper mapper;

    @Value("${ddxz.supper-tenant.name}")
    private String supperTenant;

    public LiquibaseServiceImpl(DataSource dataSource, SpringLiquibase liquibase, TenantMapper mapper) {
        this.dataSource = dataSource;
        this.liquibase = liquibase;
        this.mapper = mapper;
    }
}
